Next | Prev | Up | Top | Contents | Index

Example Conversion Problem

The code in Example 8-6 shows typical logic in a uniprocessor character driver.

Example 8-6 : Uniprocessor Upper-Half Wait Logic

s = splvme();
flag |= WAITING;
while (flag & WAITING) {
   sleep(&flag, PZERO);
}
splx(s);
The upper half calls the splvme() function with the intention of blocking interrupts, and thus preventing execution of this driver's interrupt handler while the flag variable is updated. In a multiprocessor this is ineffective because at best it sets the interrupt level on the current CPU. The interrupt handler can execute on another CPU and change the variable.

The corresponding interrupt handler is sketched in Example 8-7.

Example 8-7 : Uniprocessor Interrupt Logic

if (flag & WAITING) {
   wakeup(&flag);
   flag &= ~WAITING;
}
The interrupt handler could execute on another CPU, and test the flag after the upper half has called splvme() and before it has set WAITING in flag. The interrupt is effectively lost. This would happen rarely and would be hard to repeat, but it would happen and would be hard to trace.

A more reliable, and simpler, technique is to use a semaphore. The driver defines a global semaphore:

static sema_t sleeper;

A driver with multiple devices would have a semaphore per device, perhaps as an array of sema_t items indexed by device minor number.

The semaphore (or array) would be initialized to a starting value of 1 in the pfxinit() or pfxstart() entry:

void hypo_start()
{
...
   initnsema(&sleeper,1,"sleeper");
}
After the upper half started a device operation, it would await the interrupt using psema():

psema(sleeper,PZERO);

The PZERO argument makes the wait immune to signals. If the driver should wake up when a signal is sent to the calling process (such as SIGINT or SIGTERM), the second argument can be PCATCH. A return value of -1 indicates the semaphore was posted by a signal, not by a vsema() call.

The interrupt handler would use vsema() or cvsema() to post the semaphore. The use of cvsema() ensures that the semaphore is not incremented past 1, in the event that it is posted from more than one location (as from a timeout or a signal handler).


Next | Prev | Up | Top | Contents | Index